package dummy.sampleapp
import java.io.File
import mars.ns.core.Network
import mars.ns.Simulation
import mars.ns.core.Node
import mars.io.IO
import mars.io.formatters.NetXMLFormatter
import mars.ns.TurnSimulation
import mars.ns.selectors.ConnectSometimesRandomly
import mars.ns.statechangers.ConnectedStateChange
import mars.ns.RoundSimulation
import mars.ns.stat.Statistics
import mars.ns.visualisation.VisualisationListener
import mars.ns.listeners.SimulationAdapter
import mars.ns.core.LinkType
import mars.io.formatters.StatsXMLFormatter

object SampleApp {
  
  def usage: String = {
     return "Usage: SampleApp [nbOfNodes] <options>\n\n" +
     "[nbOfNodes] should be an integer value representing the number of nodes you wish to have in the network. This value will default to 50 if omitted.\n\n" +
     "Options:\n" +
     "-h --help \t\t\t\t\t print this message\n" +
     "--simulation-type=[round|turn|event] \t\t selects the type of simulation that will be run, this vlaue defaults to turn if omitted or malformed\n" +
     "--simmulation-iterations=[count] \t\t the number of iterations you wish to run; this value will default to 20 if omitted\n" +
     "--network-save-file=[file] \t\t\t should point to a file where you wish to save the generated network at the end of the simulation, nothing will be saved if this option is omitted\n" +
     "--network-load-file=[file] \t\t\t should point to a file from where you wish to load an existing network, nothing will be loaded if this option is omitted. [nbOfNodes] will be inored if this option is given\n" +
     "--stats-save-file=[file] \t\t\t should point to a file where you wish to save the gathered statistics, nothing will be saved if this option is omitted\n" +
     "--stats-interval=[count] \t\t\t the interval at wich statistical data will be gathered, this value will default to 5 if omitted\n" +
     "--visualize \t\t\t use prefuse graph visualizations\n"
  }
  
  val TURN_SIM = 0
  val ROUND_SIM = 1
  val EVENT_SIM = 2
  
  var simulationType = 0
  
  var loadNetwork = false
  var loadNetworkFile: File = null
  
  var saveNetwork = false
  var networkFile: File = null
  
  var saveStats = false
  var statsFile: File = null
  
  var statsInterval = 5
  
  var visualize = true
  
  var iterationCount = 500
  var simulation: Simulation[Node] = null
  var network: Network[Node] = null
  
  var nbOfNodes = 50
  
  
  def main(args: Array[String]): Unit = {
	  println("Welkom to the random graph dynamics simulator v1.337!\n")
	  
	  args.foreach( arg => {
		  if(arg.toLowerCase.matches("(-h|--help)")) {
			  println(usage)  
			  System.exit(0)
		  }
		  if(arg.toLowerCase.matches("--simulation-type=(round|turn|event)")) {
			  arg.split("=").apply(1) match {
			    	case s if s == "turn" => simulationType = TURN_SIM
			    	case s if s == "round" => simulationType = ROUND_SIM
			    	case s if s == "event" => simulationType = EVENT_SIM
			    	case _ => simulationType = TURN_SIM
			  }
		  }
		  if(arg.toLowerCase.matches("--simulation-iterations=%d+")) {
			  try { 
			    iterationCount = arg.split("=").apply(1).toInt
			  } catch  {
			    case _ => iterationCount = 20
			  }
		  }
		  if(arg.toLowerCase.matches("--network-save-file=*")) {
			  try {
				  networkFile = new File(arg.split("=").apply(1))
				  if(networkFile.exists())
					  saveNetwork = true
			  } catch {
			    	case e: Exception => 
			    	  	e.printStackTrace
			    	  	saveNetwork = false
			  }
		  }
		  if(arg.toLowerCase.matches("--network-load-file=*")) {
			  try {
				  loadNetworkFile = new File(arg.split("=").apply(1))
				  if(loadNetworkFile.exists())
					  loadNetwork = true
			  } catch {
			    	case e: Exception => 
			    	  	e.printStackTrace
			    	  	loadNetwork = false
			  }
		  }
		  if(arg.toLowerCase.matches("--stats-save-file=*")) {
			  try {
				  statsFile = new File(arg.split("=").apply(1))
				  if(statsFile.exists())
					  saveStats = true
			  } catch {
			    	case e: Exception => 
			    	  	e.printStackTrace
			    	  	saveStats = false
			  }
		  }
		  if(arg.toLowerCase.matches("--stats-interval=%d+")) {
			  try { 
			    statsInterval = arg.split("=").apply(1).toInt
			  } catch  {
			    case _ => statsInterval = 5
			  }
		  }
		  if(arg.toLowerCase.matches("--visualize")) {
			  visualize = true
		  }
	  })
	  
	  if(loadNetwork) {
		  network = IO.getInstance(loadNetworkFile, new NetXMLFormatter).load
	  } else {
		  if (args.size > 0 && args.apply(0).matches("%d+")) {
			  nbOfNodes = args.apply(0).toInt
		  }
		  var nodes : List[Node] = Nil
		  for(i<- 0 until 100)
			  nodes = new Node::nodes
			  
		  network = new Network(nodes)
	  }
	  
	  simulationType match {
	      case TURN_SIM =>
	        	simulation = new TurnSimulation(network, iterationCount) with ConnectSometimesRandomly[Node] with ConnectedStateChange[Node]
	      case ROUND_SIM =>
	        	simulation = new RoundSimulation(network, iterationCount) with ConnectSometimesRandomly[Node] with ConnectedStateChange[Node]
	      case EVENT_SIM =>
	        	throw new UnsupportedOperationException("caused by: OutOfTimeException")
	  }
	  
	  var stats = new Statistics[Node](statsInterval)
	  
	  simulation.subscribe(stats)
	  
	  if(visualize) {
		  simulation.subscribe(new VisualisationListener[Node](network))
	  }
	  
	  simulation.subscribe(new SimulationAdapter[Node]() {
		  override def update(net: Network[Node], iter: Int) = {
			  println("iteration " + iter + " comleted")
		  }
		  
		  override def edgeAdded(from : Node, to:Node, lType :LinkType) {
			  println("edge added from [" + from + "] to [" + to + "] linkType = " + lType.getClass.getSimpleName)
		  }
		  
		  override def nodeChanged(node :Node) {
			  println("Node [" + node + "] has changed")
		  }
	  })
	  
	  simulation.run
	  
	  if(saveNetwork) {
		  IO.getInstance(networkFile, new NetXMLFormatter).save(network)
		  println("Network was saved to file " + networkFile.getAbsolutePath())
	  }
	  
	  if(saveStats) {
		  IO.getInstance(statsFile, new StatsXMLFormatter).save(stats)
		  println("Statistics have been saved to file " + statsFile.getAbsolutePath())
	  }
	  
	  println("Thank you for using the random graph dynamics simulator v1.337!")
	  println("Have a nice day!")
		  
  }

}